/**
 * Copyright (c) 2009 Netflix-Flex_API Contributors.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do 
 * so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 * */
package com.netflix.webapis.users
{
	import com.netflix.webapis.ParamsBase;
	import com.netflix.webapis.ServiceBase;
	import com.netflix.webapis.ServiceFault;
	import com.netflix.webapis.catalog.vo.CatalogTitleVO;
	import com.netflix.webapis.events.NetflixFaultEvent;
	import com.netflix.webapis.events.NetflixResultEvent;
	import com.netflix.webapis.users.events.UsersFaultEvent;
	import com.netflix.webapis.users.events.UsersResultEvent;
	import com.netflix.webapis.users.params.QueueParams;
	import com.netflix.webapis.users.vo.NetflixUserVO;
	import com.netflix.webapis.users.vo.PreferredFormatVO;
	import com.netflix.webapis.users.vo.QueueItemVO;
	import com.netflix.webapis.xml.NetflixXMLUtil;
	
	import flash.net.URLRequest;
	import flash.net.navigateToURL;
	
	import mx.rpc.AsyncToken;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.HTTPService;
	
	import org.iotashan.oauth.OAuthRequest;
	import org.iotashan.oauth.OAuthSignatureMethod_HMAC_SHA1;

	/**
	* Result Event.
	*/	
	[Event(name="result",type="com.netflix.webapis.users.events.UsersResultEvent")]
	/**
	* Fault Event.
	*/	
	[Event(name="fault",type="com.netflix.webapis.users.events.UsersFaultEvent")]
	
	/**
	 * User Services.
	 * @author jonbcampos
	 * 
	 */	
	public class UserService extends ServiceBase
	{
		protected static const USERS_URL:String = NETFLIX_BASE_URL+"users";
		protected static const QUEUES_PART:String = "queues";
		protected static const DISC_PART:String = "disc";
		protected static const INSTANT_PART:String = "instant";
		
		protected static const AVAILABLE_PART:String = "available";
		protected static const SAVED_PART:String = "saved";
		
		protected static const RECOMMENDATION_PART:String = "recommendations";
		
		public static const DISC_QUEUE_SERVICE:String = "discQueue";
		public static const INSTANT_QUEUE_SERVICE:String = "instantQueue";
		public static const DISC_AVAIL_QUEUE_SERVICE:String = "discAvailQueue";
		public static const INSTANT_AVAIL_QUEUE_SERVICE:String = "instantAvailQueue";
		public static const INSTANT_SAVED_QUEUE_SERVICE:String = "instantSavedQueue";
		public static const RECOMMENDATION_SERVICE:String = "recommendation";
		public static const ADD_DISC_SERVICE:String = "addDisc";

		public function UserService()
		{
			super();
		}
		
		//----------------------------
		//
		// Public Variables
		//
		//----------------------------
		[Bindable]
		[Inspectable(enumeration="discQueue,instantQueue,discAvailQueue,instantAvailQueue,instantSavedQueue,recommendation,addDisc",defaultValue="discQueue")]
		public var type:String = DISC_QUEUE_SERVICE;
		
		//----------------------------
		//
		// Public Methods
		//
		//----------------------------
		/**
		 * Calls for the user info. Requires that you have already called the 
		 * <code>AccessTokenService.getAccessToken()</code>.
		 * 
		 * @see com.netflix.webapis.authenticate.AccessTokenService#getAccessToken() 
		 * 
		 */		
		public function getUserInfo():void
		{
			var service:HTTPService = new HTTPService();  
			service.addEventListener(ResultEvent.RESULT, userInfoResult);  
			service.addEventListener(FaultEvent.FAULT, userInfoFault);  
			service.resultFormat = "e4x";
			var req:OAuthRequest = new OAuthRequest("GET", NETFLIX_BASE_URL + "users/" + userId, null, consumer, accessToken);  
			service.url = req.buildRequest(new OAuthSignatureMethod_HMAC_SHA1(), OAuthRequest.RESULT_TYPE_URL_STRING);  
			service.send();
		}
		
		/**
		 * @private
		 * Receives user info, parses xml into a <code>NetflixUserVO</code>, 
		 * and dispatches result event. 
		 * @param event
		 * 
		 */		
		private function userInfoResult(event:ResultEvent):void
		{
			//set vars
			var userXML:XML = event.result as XML;
			var user:NetflixUserVO = new NetflixUserVO();
			//attributes
			user.userId = userXML.user_id;
			user.firstName = userXML.first_name;
			user.lastName = userXML.last_name;
			user.canInstantWatch = Boolean(userXML.can_instant_watch);
			//preferred formats
			user.preferredFormats = new Array();
			for each(var preferredFormatXML:XML in userXML..category){
				var pvo:PreferredFormatVO = new PreferredFormatVO();
				pvo.label = preferredFormatXML.@label;
				pvo.term = preferredFormatXML.@term;
				user.preferredFormats.push(pvo);
			}
			//links
			user.queuesLink = userXML.link[0].@href;
			user.rentalHistoryLink = userXML.link[1].@href;
			user.recommendationsLink = userXML.link[2].@href;
			user.titleStatesLink = userXML.link[3].@href;
			user.ratingsLink = userXML.link[4].@href;
			user.reviewsLink = userXML.link[5].@href;
			user.atHomeLink = userXML.link[6].@href;
			user.feedsLink = userXML.link[7].@href;
			dispatchEvent(new UsersResultEvent(UsersResultEvent.RESULT,user))
		}
		
		/**
		 * @private
		 * Dispatches fault. 
		 * @param event
		 * 
		 */		
		private function userInfoFault(event:FaultEvent):void
		{
			dispatchEvent(new UsersFaultEvent(UsersFaultEvent.FAULT,new ServiceFault(event.fault.faultCode,event.fault.faultString,event.fault.faultDetail)));
		}
		
		/**
		 * @inherit
		 */		
		override public function send(parameters:ParamsBase = null):void
		{
			super.send(parameters);
			
			switch(type)
			{
				case DISC_QUEUE_SERVICE:
					discQueueService( parameters );
				break;
				case INSTANT_QUEUE_SERVICE:
					instantQueueService( parameters );
				break;
				case DISC_AVAIL_QUEUE_SERVICE:
					discAvailQueueService( parameters );
				break;
				case INSTANT_AVAIL_QUEUE_SERVICE:
					instantAvailQueueService( parameters );
				break;
				case INSTANT_SAVED_QUEUE_SERVICE:
					instantSavedQueueService( parameters );
				break;
				case RECOMMENDATION_SERVICE:
					recommendationService( parameters );
				break;
				case ADD_DISC_SERVICE:
					addDiscService( parameters );
				break;
			}
		}
		
		public function discQueueService(params:ParamsBase=null):void
		{
			handleServiceLoading(USERS_URL,NetflixResultEvent.DISC_QUEUE_RESULT,params);
		}
		
		public function instantQueueService(params:ParamsBase=null):void
		{
			handleServiceLoading(USERS_URL,NetflixResultEvent.INSTANT_QUEUE_RESULT,params);
		}
		
		public function discAvailQueueService(params:ParamsBase=null):void
		{
			handleServiceLoading(USERS_URL,NetflixResultEvent.DISC_AVAIL_QUEUE_RESULT,params);
		}
		
		public function instantAvailQueueService(params:ParamsBase=null):void
		{
			handleServiceLoading(USERS_URL,NetflixResultEvent.INSTANT_AVAIL_QUEUE_RESULT,params);
		}
		
		public function instantSavedQueueService(params:ParamsBase=null):void
		{
			handleServiceLoading(USERS_URL,NetflixResultEvent.INSTANT_SAVED_QUEUE_RESULT,params);
		}
		
		public function recommendationService(params:ParamsBase=null):void 
		{
			handleServiceLoading(USERS_URL,NetflixResultEvent.RECOMMENDATION_RESULT,params);
		}
		
		public function addDiscService(params:ParamsBase = null):void {
			handleServiceLoading(USERS_URL, NetflixResultEvent.UPDATE_QUEUE_RESULT, params);
		}
		
		protected override function handleServiceLoading(methodString:String, dispatchType:String, params:ParamsBase=null):void
		{
			var sendQuery:String = methodString;
			var typeQuery:String;
			
			var queryXMLService:HTTPService = new HTTPService();
			queryXMLService.method = "GET";
			
			if(params != null)
			{
				switch(dispatchType)
				{
					case NetflixResultEvent.DISC_QUEUE_RESULT:
						sendQuery += "/" + userId + "/" + QUEUES_PART + "/" + DISC_PART;
					break;
					case NetflixResultEvent.INSTANT_QUEUE_RESULT:
						sendQuery += "/" + userId + "/" + QUEUES_PART + "/" + INSTANT_PART;
					break;
					case NetflixResultEvent.DISC_AVAIL_QUEUE_RESULT:
						sendQuery += "/" + userId + "/" + QUEUES_PART + "/" + DISC_PART + "/" + AVAILABLE_PART;
					break;
					case NetflixResultEvent.INSTANT_AVAIL_QUEUE_RESULT:
						sendQuery += "/" + userId + "/" + QUEUES_PART + "/" + INSTANT_PART + "/" + AVAILABLE_PART;
					break;
					case NetflixResultEvent.DISC_SAVED_QUEUE_RESULT:
						sendQuery += "/" + userId + "/" + QUEUES_PART + "/" + DISC_PART + "/" + SAVED_PART;
					break;
					case NetflixResultEvent.INSTANT_SAVED_QUEUE_RESULT:
						sendQuery += "/" + userId + "/" + QUEUES_PART + "/" + INSTANT_PART + "/" + SAVED_PART;
					break;
					case NetflixResultEvent.RECOMMENDATION_RESULT:
						sendQuery += "/" + userId + "/" + RECOMMENDATION_PART;
					break;
					case NetflixResultEvent.UPDATE_QUEUE_RESULT:
						sendQuery += "/" + userId + "/" + QUEUES_PART + "/" + DISC_PART;
						queryXMLService.method = "POST";
					break;
						
				}
			}
			
			var tokenRequest:OAuthRequest = new OAuthRequest(queryXMLService.method,sendQuery,(params as QueueParams).toObject(),consumer,accessToken);
			queryXMLService.url = tokenRequest.buildRequest(SIG_METHOD);
			trace(tokenRequest.buildRequest(SIG_METHOD));
			queryXMLService.resultFormat = "e4x";
			queryXMLService.addEventListener(ResultEvent.RESULT,onCompleteHandler);
			queryXMLService.addEventListener(FaultEvent.FAULT,onFault);
			queryXMLService.send();
		
			function onCompleteHandler(event:ResultEvent):void
			{
				queryXMLService.removeEventListener(ResultEvent.RESULT,onCompleteHandler);
				var queryXML:XML = event.result as XML;
				
				if(queryXML.Error == undefined)
					formatAndDispatch(queryXML, dispatchType);
				else
					dispatchFault(new ServiceFault(NetflixFaultEvent.API_RESPONSE, queryXML.Error, queryXML.Error.Message));
			}
			
			function onFault(event:FaultEvent):void
			{
				queryXMLService.removeEventListener(FaultEvent.FAULT,onFault);
				navigateToURL(new URLRequest(tokenRequest.buildRequest(SIG_METHOD)));
				dispatchFault(new ServiceFault(event.fault.faultCode,event.fault.faultString,event.fault.faultDetail));
			}
		} 

		protected override function formatAndDispatch(returnedXML:XML, dispatchType:String):void {
			/* if(increment == 0) lastResult = new Array();
			
			var len:int = lastResult.length;
			numberOfResults = returnedXML.number_of_results;
			startIndex = returnedXML.start_index;
			resultsPerPage = returnedXML.results_per_page; */
			
			var resultsArray:Array = new Array();
			var resultNode:XML;
			
			//loop through child nodes and build value objects based on catagory type
			switch(dispatchType)
			{
				case NetflixResultEvent.DISC_QUEUE_RESULT:
				case NetflixResultEvent.INSTANT_QUEUE_RESULT:
				case NetflixResultEvent.DISC_AVAIL_QUEUE_RESULT:
				case NetflixResultEvent.INSTANT_AVAIL_QUEUE_RESULT:
				case NetflixResultEvent.DISC_SAVED_QUEUE_RESULT:
				case NetflixResultEvent.INSTANT_SAVED_QUEUE_RESULT:
				case NetflixResultEvent.UPDATE_QUEUE_RESULT:
					if (returnedXML..etag != null)
						NetflixXMLUtil.handleETagNode(returnedXML..etag[0]);
					for each (resultNode in returnedXML..queue_item) {
						var catItemVO:CatalogTitleVO = NetflixXMLUtil.handleCatalogTitleNode(resultNode, new QueueItemVO);
						resultsArray.push(catItemVO);
					}
				break;
				case NetflixResultEvent.RECOMMENDATION_RESULT:
					for each (resultNode in returnedXML..recommendation) {
						var catalogItem:CatalogTitleVO = NetflixXMLUtil.handleCatalogTitleNode(resultNode, new QueueItemVO);
						resultsArray.push(catalogItem);
					}
			}
			dispatchResult(resultsArray,dispatchType, returnedXML);
		}
	}
}